package core;

import java.util.ArrayList;

import parsing.Parser;

import functions.Function;
import functions.FunctionIF;

public class FixedPointIteration extends Method {

	private double initialX;
	private double finalX;
	private int counter = 0;
	private double startPoint;
	private ArrayList<Point> res;
	private Function fn;

	public FixedPointIteration(int numOfIteration, double precision, double a,
			double b, double startP) {
		super(numOfIteration, precision);
		initialX = a;
		finalX = b;
		startPoint = startP;
		res = new ArrayList<Point>();
	}

	public boolean check(Function f) {
		FunctionIF diff = f.diff();
		if (f.eval(initialX) >= initialX && f.eval(initialX) <= finalX
				&& f.eval(finalX) >= initialX && f.eval(finalX) <= finalX
		// && Math.abs(diff.eval(initialX)) < 1
		// && Math.abs(diff.eval(finalX)) < 1
		) {
			return true;
		}
		return false;
	}

	@Override
	public ArrayList<Point> run(Function f) throws Exception {
		if (check(f)) {
			double p = startPoint;
			while (counter < numOfIteration) {
				p = f.eval(p);
				Point gX = new Point(p);
				res.add(gX);
				if (res.size() > 1
						&& res.get(res.size() - 1).getX() == res.get(
								res.size() - 2).getX()) {
					return res;
				}
				counter++;
			}
		} else {
			throw new Exception("Can't evaluate !");
		}
		return res;
	}

	@Override
	public double getErrorBound() {
		double result = 0;
		result = (Math.pow(getK(fn), counter) / (1 - getK(fn)))
				* (res.get(1).getX() - res.get(0).getX());
		return result;
	}

	public int getK(Function f) {
		fn = f;
		if (f.diff().eval(initialX) > f.diff().eval(finalX))
			return (int) (f.diff().eval(initialX)) + 1;
		else
			return (int) (f.diff().eval(finalX)) + 1;
	}

	/**
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		Parser p = new Parser();
		Function f = p.parse("1 + x^1 - x^2/4");
		FixedPointIteration fPI = new FixedPointIteration(10, 0.00001, 1, 3,
				1.6);
		fPI.run(f);
		for (int i = 0; i < fPI.res.size(); i++) {
			System.out.println("x: " + fPI.res.get(i).getX());
		}
		System.out
				.println("The value of x such taht f(x) ~ 0 : \n==================================");
		System.out.println("x= : " + fPI.res.get(fPI.res.size() - 1).getX());
		System.out.println("the # iterations is :" + fPI.counter);
	}

}
